package fluxx.draft;

import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;

public class GameState {
	
	public static final int INIT_HAND_SIZE = 3;
	private int turnIndex;

	// TODO Do something about all these public stuff. What must be visible? Maybe immutable-getters instead.
	public final Player[] players;
	public final CardPile freshCards;
	private CardSet discardPile = new CardSet();
	
	public Goal goal = null; // TODO LATER Support multiple goals
	private int playedAmount;
	public RuleSet2 rules = new RuleSet2(this);
	
	private PropertyChangeSupport change = new PropertyChangeSupport(this);
	
	public GameState (Deck deck, int numPlayers) {
		assert numPlayers > 1;
		freshCards = new CardPile(deck.getDeck());
		
		// Create players
		players = new Player[numPlayers];
		for (int i = 0; i < numPlayers; i++) {
			Player playerToAdd = new Player();
			for (int j = 0; j < INIT_HAND_SIZE; j++)
				playerToAdd.give(takeFresh());
			players[i] = playerToAdd;
		}
	}
	public Card takeFresh() {
		if (freshCards.size() == 0) {
			recycle();
		}
		return freshCards.take();
	}
	private void recycle() {
		for (Card card : discardPile) {
			freshCards.add(card);
		}
		discardPile = new CardSet();
		freshCards.shuffle();
	}
	public CardPile getFreshCards() {
		return freshCards; // TODO Immutable view?
	}
	public AbstractCardSet getDiscardPile() {
		return discardPile; // TODO Immutable view?
	}
	/**
	 * Adds a card to the discard pile. This does not take into account the
	 * source of the card.
	 * @param The card to discard. It is not removed from the source.
	 */
	public void discard(Card card) {
		discardPile.add(card);
	}
	public Player currentPlayer() {
		return players[turnIndex];
	}
	private void passTurn() {
		rules.applyPassTurn();
		turnIndex = (turnIndex+1) % players.length;
		playedAmount = 0;
	}
	public int playsLeft() {
		return rules.getPlayAmount() - playedAmount;
	}
	
	public void playCard(Player player, Card playedCard) throws GameOverException {
		player.take(playedCard); // TODO Player.take() catch exception?
		playedAmount++;
		playedCard.bePlayed(this, player);
		if (!mayPlay()) {
			passTurn();
			change.firePropertyChange("turn", false, true);
		}
	}

	public void checkGoalSatisfied() throws GameOverException {
		if (/*goal != null && goal.hasWinner(this)*/ rules.isGoalSatisfied()) {
			throw new GameOverException(goal.getWinner(this));
		}
	}
	public AbstractCardSet demandPick(AbstractCardSet set, int amount, String reason) {
		// TODO Until there's a View, this method just picks randomly.
		CardSet takenCards = new CardSet();
		for (int i = 0; i < amount; i++) {
			int index = (int) (Math.random() * set.size());
			takenCards.add(set.get(index));
		}
		return takenCards;
	}
	public Card demandPickOne(AbstractCardSet set, String reason) {
		return demandPick(set, 1, reason).get(0);
	}
	 // TODO Fix CardSet and RuleSet2 hierarchy
	public Rule demandPickOne(RuleSet2 set, String reason) {
		int index = (int) (Math.random() * set.size());
		return set.get(index);
	}
	public boolean mayPlay() {
		return (playsLeft() > 0 && currentPlayer().getHand().size() > 0);
	}
	public void addListener(PropertyChangeListener listener) {
		change.addPropertyChangeListener(listener);
	}
}
